package com.iam.api.controller;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.iam.core.base.BaseCommonController;
import com.iam.core.base.BaseCommonService;
import com.iam.core.config.IamApplicationconfig;
import com.iam.core.entities.IFilter;
import com.iam.core.entities.IParams;
import com.iam.core.entities.Result;
import com.iam.core.model.SysArgs;
import com.iam.core.model.SysFile;
import com.iam.core.service.ArgsService;
import com.iam.core.service.SysFileService;
import com.iam.api.model.Information;
import com.iam.api.model.Sign;
import com.iam.api.service.InformationService;
import com.iam.api.service.SignService;
import com.iam.core.utils.ResultUtil;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/api/sign")
public class SignController extends BaseCommonController<Sign> {

    @Autowired
    private SignService<Sign> service;

    @Autowired
    private InformationService<Information> informationService;

    @Autowired
    private SysFileService<SysFile> fileService;

    @Autowired
    private ArgsService argsService;

    @Autowired
    private IamApplicationconfig appConfig;


    @Override
    public BaseCommonService<Sign> getiService() {
        return service;
    }

    @Override
    public Result index(@RequestBody IParams params) {
        int loginIdAsInt = StpUtil.getLoginIdAsInt();

        if(loginIdAsInt != 1) {
            List<IFilter> filters = params.getFilters();
            IFilter iFilter = new IFilter();
            iFilter.setFieldName("creator");
            iFilter.setCompare("=");
            iFilter.setFieldValue(loginIdAsInt);
            filters.add(iFilter);
        }

        return ResultUtil.success(super.index(params));
    }

    /**
     * 编辑 更新
     *
     * @param entity
     */
    @PutMapping
    public Result update(@RequestBody Sign entity) {
        entity.setUpdateAt(new Date());
        return super.update(entity);
    }

    /**
     * 获取待替换的参数
     * 参数包括
     * 1. 选项
     * 2. 项目信息
     * @param sign
     * @return
     */
    public Map<String, String> getReplacements(Sign sign) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        // 查询所有注入的参数
        List<SysArgs> args = argsService.list(new QueryWrapper<SysArgs>());
        // 将选项加入待替换
        Map<String, String> replacements = new HashMap<>();
        for (SysArgs arg : args) {
            replacements.put("${"+ arg.getCode() +"}", arg.getValue());
        }
        // 将项目信息加入
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "合作单位" +"}", sign.getCompany());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "出函银行" +"}", sign.getBankName());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "保函类型" +"}", sign.getBusType());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "直开/转开" +"}", sign.getInvoiceType());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "客户名称" +"}", sign.getCusName());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "信用代码" +"}", sign.getCreditCode());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "法人姓名" +"}", sign.getLegalName());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "法人职务" +"}", sign.getLegalPosition());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "联系方式" +"}", sign.getPhone());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "企业地址" +"}", sign.getCompanyAddress());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "担保期限" +"}", sign.getGuaranteeDate());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "担保金额" +"}", sign.getGuaranteeAmount());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "担保金额大写" +"}", sign.getGuaranteeAmountUpcase());
        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "项目名称" +"}", sign.getProjectName());

        replacements.put("${"+ appConfig.getSignArgsPrefix() + ":" + "受益人" +"}", sign.getBeneficiary());
        return replacements;
    }

    @GetMapping("/zip")
    public ResponseEntity<StreamingResponseBody> zip(@RequestParam("id") Serializable id, HttpServletResponse response) throws IOException {
        Sign sign = service.getById(id);
        // 获取待替换的参数
        Map<String, String> replacements = getReplacements(sign);
        // 设置响应头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDisposition(ContentDisposition.attachment()
                .filename("documents.zip").build());

        List<Information> list = informationService.list(new LambdaQueryWrapper<Information>()
                .eq(Information::getBankName, sign.getBankName())
                .eq(Information::getCompany, sign.getCompany())
                .eq(Information::getInvoiceType, sign.getInvoiceType()));
        if (!CollectionUtils.isEmpty(list)) {
            // 流式处理ZIP压缩
            StreamingResponseBody stream = out -> {
                try (ZipOutputStream zos = new ZipOutputStream(out)) {
                    for (Information info : list) {
                        SysFile file = fileService.getById(info.getFileId());
                        Path filePath = Paths.get(file.getFilePath());
                        if (!Files.exists(filePath)) continue;

                        if(file.getFileName().endsWith(".docx")) {
                            FileInputStream fis = new FileInputStream(filePath.toString());
                            XWPFDocument document = new XWPFDocument(fis);
                            // 接下来进行模板替换操作
                            replaceInDocx(document, replacements);
                            // 添加ZIP条目
                            ZipEntry entry = new ZipEntry(file.getFileName().toString());
                            zos.putNextEntry(entry);

                            // 文件流拷贝
                            document.write(zos);
                            document.close();
                        } else {
                            ZipEntry entry = new ZipEntry(file.getFileName().toString());
                            zos.putNextEntry(entry);

                            FileInputStream fis = new FileInputStream(file.getFilePath());
                            byte[] buffer = new byte[1024 * 8]; // 8KB缓冲区
                            int bytesRead;
                            // 循环读取文件内容并写入输出流
                            while ((bytesRead = fis.read(buffer)) != -1) {
                                zos.write(buffer, 0, bytesRead);
                            }
                            zos.flush(); // 确保数据全部写入
                        }


                        zos.closeEntry();
                    }
                    zos.finish();
                }
            };

            return new ResponseEntity<>(stream, headers, HttpStatus.OK);
        }
        return null;
    }

    @Override
    public String getMouduleName() {
        return "签约资料";
    }

    /**
     * 替换.docx文档中的占位符
     */
    public static void replaceInDocx(XWPFDocument doc, Map<String, String> params) throws IOException {
        try {

            // 处理段落文本
            for (XWPFParagraph p : doc.getParagraphs()) {
                replaceInRuns(p.getRuns(), params);
            }

            // 处理表格文本
            for (XWPFTable tbl : doc.getTables()) {
                for (XWPFTableRow row : tbl.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph p : cell.getParagraphs()) {
                            replaceInRuns(p.getRuns(), params);
                        }
                    }
                }
            }
        } finally {

        }
    }

    private static void replaceInRuns(List<XWPFRun> runs, Map<String, String> params) {
        for (XWPFRun run : runs) {
            System.out.println(run.getTextPosition() + "_____" + run.getText(0));

            String text = run.getText(0);
            if (text != null) {
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    if (text.contains(entry.getKey())) {
                        text = text.replace(entry.getKey(), entry.getValue());
                        run.setText(text, 0);
                    }
                }
            }
        }
    }

}
